eutils = function(host = 'eutils.ncbi.nlm.nih.gov', path='/entrez/eutils') {
   
   source('url.r', local=TRUE)
   
   eutil = function(eutil, query) {
      library(XML)
      url = url(host=host, path=sprintf('%s/%s.fcgi', sub('/*$', '', path), eutil), query=query)$url
      object = list(
         eutil=eutil,
         url=url,
         query=query,
         response=xmlInternalTreeParse(url))
      class(object) = c(eutil, 'eutil', class(object))
      object }
   
   einfo = function(database=NULL) {
      if (is.null(database)) {
         object = eutil('einfo', '')
         object$databases = xpathSApply(object$response, '//DbList/DbName', xmlValue) }
      else {
         object = eutil('einfo', sprintf('db=%s', database))
         response = object$response
         features = c(
            list(
               fields=as.data.frame(stringsAsFactors=FALSE, split(
                  xpathSApply(response, '//FieldList/Field/*', xmlValue),
                  xpathSApply(response, '//FieldList/Field[position()=1]/*', xmlName))),
               links=as.data.frame(stringsAsFactors=FALSE, split(
                  xpathSApply(response, '//LinkList/Link/*', xmlValue),
                  xpathSApply(response, '//LinkList/Link[position()=1]/*', xmlName)))),
            lapply(
               list(id='DbName', name='MenuName', description='Description', count='Count', update='LastUpdate'),
               function(name) 
                  xpathSApply(response, sprintf('/*/*/%s', name), xmlValue)))
         object[names(features)] = features }
      return (object) }
      
   esearch = function(database, query, history=FALSE, webenv=NULL, 
         key=NULL, tool='reutils', email=NULL, field=NULL, reldate=NULL, 
         mindate=NULL, maxdate=NULL, datetype=NULL, retstart=0, 
         retmax=100, retmode='xml', rettype='uilist', sort=NULL) {
      parameters = c(db=database, term=query, history=history, 
         WebEnv=webenv, key=key, tool=tool, email=email, field=field, 
         reldate=reldate, mindate=mindate, maxdate=maxdate, 
         datetype=datetype, retstart=retstart, retmax=retmax, 
         retmode=retmode, rettype=rettype, sort=sort)
      object = eutil('esearch', do.call(query, as.list(parameters)))
      object }
      
   list(einfo=einfo, esearch=esearch) }


local({
   format = '% 10s: %s\n'
   functions = list(
      str.eutil = function(eutil) {
         with(eutil, sprintf(
            paste(rep(format, 2), collapse=''),
               'EUtil', eutil,
               'Query', if(query != '') query else '(none)')) },
      print.eutil = function(eutil) {
         cat(str(eutil)) })
   for (name in names(functions))
      assign(name, functions[[name]], env=globalenv()) })
